/* freeircd nickserv.c
 *
 * Iniciado em 28/08/2006
 */

#define _GNU_SOURCE
#include <errno.h>
#include "misc.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdbool.h>
#include <time.h>
#include <stdarg.h>
#include <dirent.h>
#include <ctype.h>

#include "ggets.h"
#include "types.h"
#include "configuration.h"
#include "getinfo.h"
#include "alloc.h"

#include "debug.h"

#define HELP_UNKNOWN_AJOIN_COMMAND -4
#define HELP_UNKNOWN_NOTES_COMMAND -3
#define HELP_UNKNOWN_SET_COMMAND -2
#define HELP_UNKNOWN_COMMAND -1
#define HELP_MAIN 0
#define HELP_IDENTIFY 1
#define HELP_REGISTER 2
#define HELP_INFO 3
#define HELP_SET 4
#define HELP_SET_PASSWORD 5
#define HELP_SET_EMAIL 6
#define HELP_SET_URL 7
#define HELP_SET_LOCATION 8
#define HELP_SET_KILL 9
#define HELP_DROP 10
#define HELP_GHOST 11
#define HELP_STATUS 12
#define HELP_NOTES 13
#define HELP_NOTES_ADD 14
#define HELP_NOTES_DEL 15
#define HELP_NOTES_LIST 16
#define HELP_AJOIN 17
#define HELP_AJOIN_NOW 18
#define HELP_AJOIN_LIST 19
#define HELP_AJOIN_ADD 20
#define HELP_AJOIN_DEL 21

static void show_nickserv_help(CLIENTS *, veryshort);
static void nickserv_identify(CLIENTS *, CHANS **, long *, CLIENTS **);
static void nickserv_register(CLIENTS *, CHANS **, USERREG **, long *, CLIENTS **);
static void nickserv_info(CLIENTS *, USERREG **, CHANS *);
static void nickserv_set(CLIENTS *);
static void nickserv_notes(CLIENTS *);
static void nickserv_ajoin(CLIENTS *,CLIENTS **, long *, CHANS **);
static void nickserv_drop(CLIENTS *, USERREG **, CHANS *);
static bool nickserv_ghost(CLIENTS *, USERREG *, CLIENTS **);
static void nickserv_status(CLIENTS *, USERREG *);
void nickserv(CLIENTS *, USERREG **, CHANS **, long *, CLIENTS **, long *);
static bool nickserv_iscommand(char *);
USERREG *get_user_reg(CLIENTS *, USERREG **, CHANS *);
void save_userreg(USERREG *);
void load_userreg(USERREG **);
static void rm_user_reg_file(char *);
void check_unused_reg(USERREG **, CHANS *);
static void free_ajoins_and_notes(USERREG *);
static void rm_ref_to_nick_reg(char *, CHANS *);
static void ajoin_all(struct reg_ajoin *, CLIENTS **, CLIENTS *, long *, CHANS **);

extern void write_sock(CLIENTS *, char *, ...);
extern void send_to_all_in_chan(CLIENTS *client, char *chan, char *str, ...);
extern inline void memerror(void *);
extern void part(CLIENTS *, CHANS **, bool, long *, bool);
extern void send_to_all(CLIENTS *, char *, ...);
extern void remove_connection(CLIENTS **, CLIENTS *);
extern void check_chans(CHANS **, long *);
extern void join(CLIENTS **, CLIENTS *, long *, CHANS **);
extern veryshort get_user_access_level(struct access_users *, char *);

static void show_nickserv_help(CLIENTS *client, veryshort flag)
{
        switch (flag)
        {
                case HELP_MAIN:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :O serviço nickserv permite que o teu nick seja registado,\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :prevenindo que outros utilizadores o usem.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Se o teu nick não for usado por um periodo\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :de %d dias, o registo e' apagado.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,REMOVE_NICK_TIMEOUT);
                        write_sock(client,":%s!%s@%s NOTICE %s :Os comandos que se seguem, permitem o registo e configuração\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :do nick; para usa-los escreve: /%s <comando>\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para obter mais informações sobre um comando especifico\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :escreve: /%s help <comando>.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :REGISTER Regista um nickname\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :IDENTIFY Identifica o teu nickname com a tua password\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :SET Altera as opções e informações do nick\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :DROP Remove o registo do teu nickname\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :GHOST \"Mata\" um utilizador a usar o teu nickname\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :INFO Mostra a informação de um utilizador\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :STATUS Mostra o status de um utilizador\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :NOTES Gere as tuas notas\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :AJOIN Gere os teus auto-joins\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        break;
                }
                case HELP_IDENTIFY:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando identify: Serve para te identificares \"dono\" de um nick.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s identify <password>\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_REGISTER:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando register: Serve para registares o teu actual nick.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s register <password>\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Nota: A password e' case sensitive\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        break;
                }
                case HELP_INFO:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando info: Serve para saberes infomação do registo de um nick.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s info <nick>\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_SET:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando set: Serve para defenir opções de um nick.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s set <comando> [...]\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para obter mais informações sobre um comando especifico\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :escreve: /%s help set <comando>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Comandos:\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :PASSWORD Muda a password do nick\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :EMAIL Muda o email do nick\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :URL Muda o url do nick\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :LOCATION Muda a localização do nick\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :KILL Muda o tempo de identificação\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        break;
                }
                case HELP_SET_PASSWORD:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando set password: Serve para mudar a password do nick.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s set password <password_antiga> <nova_password>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_SET_EMAIL:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando set email: Serve para mudar/definir o email do nick.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s set email <email>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para apagar o mail: /%s set email\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_SET_URL:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando set url: Serve para mudar/definir o url do nick.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s set url <email>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para apagar o url: /%s set url\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_SET_LOCATION:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando set location:"
                                          " Serve para mudar/definir a localização do utilizador. (ex: Leiria)\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s set location <localização>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para apagar a localização: /%s set location\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_SET_KILL:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando set kill:"
                                          " Serve para mudar o tempo de identificação do nick.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s set kill <tempo>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :O tempo e' em segundos e não pode ser inferior a %d ou superior a %d\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MIN_KILL_SEGS,MAX_KILL_SEGS);
                        break;
                }
                case HELP_UNKNOWN_SET_COMMAND:
                {
                        char *cmd=getoken(client->msg,4,' ');
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Comando set %s desconhecido\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Para mais informações escreve: /%s help set\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        free(cmd);
                        break;
                }
                case HELP_DROP:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando drop: Serve apagares o registo do teu nick.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s drop <password>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_GHOST:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando ghost:"
                                          " Serve para \"matar\" um utilizador que esta' a usar um nick teu\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s ghost <nick> <password>\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_STATUS:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando status:"
                                          " Serve para mostrar o status de um/uns utilizador/res (maximo de %d por comando)\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_STATUS_PARAMS);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s status <nick> [nick2] [nick3] [...]\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Códigos:\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :0 - offline (ou não registado)\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :1 - online mas não identificado\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :3 - online e identificado\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        break;
                }
                case HELP_NOTES:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando notes:"
                                          " Serve para gerir as tuas notas (maximo de %d)\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s notes <comando> [...]\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para obter mais informações sobre um comando especifico\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :escreve: /%s help notes <comando>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Comandos:\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :ADD Adiciona uma nota\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :DEL Apaga uma nota\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :LIST Lista todas as notas\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);

                        break;
                }
                case HELP_NOTES_ADD:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando notes add:"
                                          " Serve para adicionar uma nota\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s notes add <nota>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_NOTES_DEL:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando notes del:"
                                        " Serve para apagar uma nota\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s notes del <num_nota>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_NOTES_LIST:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando notes list:"
                                          " Serve para listar as notas\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s notes list\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_UNKNOWN_NOTES_COMMAND:
                {
                        char *cmd=getoken(client->msg,4,' ');
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Comando notes %s desconhecido\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Para mais informações escreve: /%s help notes\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        free(cmd);
                        break;
                }
                case HELP_AJOIN:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando ajoin:"
                                        " Serve para gerir os teus auto-joins (maximo de %d)\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_AJOINS_CHANS);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s ajoin <comando> [...]\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Para obter mais informações sobre um comando especifico\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :escreve: /%s help ajoin <comando>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        write_sock(client,":%s!%s@%s NOTICE %s :Comandos:\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :NOW Entra em todos os canais da lista\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :LIST Lista os canais de auto-join\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :ADD Adiciona um canal a' lista\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        write_sock(client,":%s!%s@%s NOTICE %s :DEL Apaga um canal da lista\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        break;
                }
                case HELP_AJOIN_NOW:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando ajoin now: "
                                        "Serve para entrar em todos os canais da tua lista de auto-join\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s ajoin now\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_AJOIN_LIST:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando ajoin list:"
                                        " Serve para listar em todos os canais da tua lista de auto-join\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s ajoin list\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_AJOIN_ADD:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando ajoin add: "
                                        "Serve para adicionar um canal a' tua lista de auto-join\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s ajoin add <#chan>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_AJOIN_DEL:
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Comando ajoin del: "
                                        "Serve para apagar um canal a' tua lista de auto-join\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_NOTES);
                        write_sock(client,":%s!%s@%s NOTICE %s :Sintaxe: /%s ajoin del <#chan>\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        break;
                }
                case HELP_UNKNOWN_AJOIN_COMMAND:
                {
                        char *cmd=getoken(client->msg,4,' ');
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Comando ajoin %s desconhecido\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Para mais informações escreve: /%s help ajoin\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        free(cmd);
                        break;
                }
                case HELP_UNKNOWN_COMMAND:
                {
                        char *cmd=getoken(client->msg,3,' ');
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Comando %s desconhecido\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                        write_sock(client,":%s!%s@%s NOTICE %s :Help: Para mais informações escreve: /%s help\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                        free(cmd);
                        break;
                }
        }
}

static void nickserv_identify(CLIENTS *client, CHANS **ppchans, long *channels, CLIENTS **ppclients)
{
        char *pw;
        bool already_ident=false;

        if (tknum(client->msg,' ') == 2)
        {
                show_nickserv_help(client,HELP_IDENTIFY);
                return;
        }

        if (client->reg == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :O nick %s não esta' registado.\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para saberes como o registar escreve /%s help register\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        if (client->reg->status == USER_STATUS_IDENTIFIED)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Ja' estás identificado!"
                                  " Para fins de compactibilidade vais ser deidentificado,"
                                  " e se a tua password estiver correcta identificado novamente!\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                client->reg->status=USER_STATUS_TO_IDENTIFY;
                time(&(client->reg->ident_timeout));
                client->reg->ident_timeout+=client->reg->kill_timeout;
                already_ident=true;
        }

        if (tknum(client->msg,' ') > 3) {
                write_sock(client,":%s!%s@%s NOTICE %s :Identify: Demasiados parametros\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return;
        }

        pw=getoken(client->msg,3,' ');

        if (comp(pw,client->reg->password))
        {
                char *tmp;

                if (!already_ident)
                        client->ident_failed=0;
                client->reg->status=USER_STATUS_IDENTIFIED;
                time(&(client->reg->last_time));


                free(client->reg->nome);
                if (client->name == NULL)
                        client->reg->nome=NULL;
                else
                {
                        client->reg->nome=malloc(strlen(client->name)+1);
                        memerror(client->reg->nome);
                        strcpy(client->reg->nome,client->name);
                }

                client->reg->user=client;

                free(client->reg->nick);
                client->reg->nick=malloc(strlen(client->nick)+1);
                memerror(client->reg->nick);
                strcpy(client->reg->nick,client->nick);

                save_userreg(client->reg);

                tmp=client->msg;
                client->msg=malloc(32);
                memerror(client->msg);
                strcpy(client->msg,"PART #unidentified");
                part(client,ppchans,false,channels,true);
                free(client->msg);
                client->msg=tmp;

                write_sock(client,":%s!%s@%s NOTICE %s :Password Aceite\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);

#if FORCE_JOIN_PUTEDO == 1

                tmp=client->msg;
                client->msg=malloc(32);
                memerror(client->msg);
                strcpy(client->msg,"JOIN #putedo");
                join(ppclients,client,channels,ppchans);
                free(client->msg);
                client->msg=tmp;
#endif

                ajoin_all(client->reg->ajoins,ppclients,client,channels,ppchans);
        }
        else
        {
                client->ident_failed++;
                write_sock(client,":%s!%s@%s NOTICE %s :Password incorrecta\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
        }

        free(pw);
}

static void nickserv_register(CLIENTS *client, CHANS **ppchans, USERREG **ppusers_regs, long *channels, CLIENTS **ppclients)
{
        char *pw;
        char *tmp;
        USERREG *users_lst=*ppusers_regs;

        if (tknum(client->msg,' ') == 2)
        {
                show_nickserv_help(client,HELP_REGISTER);
                return;
        }

        if (client->reg != NULL)
        {
                /*Ja' esta' registado*/
                write_sock(client,":%s!%s@%s NOTICE %s :Nick %s ja' esta' registado.\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
                return;
        }

        if (tknum(client->msg,' ') > 3)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Register: Demasiados parametros\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return;
        }

        pw=getoken(client->msg,3,' ');

        if (strlen(pw) > PASSWORD_LEN_LIMIT)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :A password não pode ter mais de %d caracteres\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,PASSWORD_LEN_LIMIT);
                free(pw);
                return;
        }

        if (strlen(pw) < PASSWORD_MIN_LEN)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :A password não pode ter menos de %d caracteres\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,PASSWORD_MIN_LEN);
                free(pw);
                return;
        }

        users_lst=alloc_user_reg_list(ppusers_regs);

        client->reg=users_lst;
        users_lst->user=client;

        users_lst->email=NULL;
        users_lst->url=NULL;
        users_lst->localizacao=NULL;
        users_lst->password=pw;
        users_lst->kill_timeout=DEFAULT_IDENTIFY_TIMEOUT;
        users_lst->never_unreg=false;

        users_lst->notas=NULL;
        users_lst->ajoins=NULL;

        users_lst->last_mask=malloc(strlen(USER_NAME)+strlen(client->md5_ip)+2);
        memerror(users_lst->last_mask);
        sprintf(users_lst->last_mask,"%s!%s",USER_NAME,client->md5_ip);

        time(&(users_lst->reg_time));
        users_lst->last_time=users_lst->reg_time;
        users_lst->online_time=0;
        users_lst->status=USER_STATUS_IDENTIFIED;

        if (client->name == NULL)
                users_lst->nome=NULL;
        else
        {
                users_lst->nome=malloc(strlen(client->name)+1);
                memerror(users_lst->nome);
                strcpy(users_lst->nome,client->name);
        }

        users_lst->nick=malloc(strlen(client->nick)+1);
        memerror(users_lst->nick);
        strcpy(users_lst->nick,client->nick);

        save_userreg(client->reg);

        tmp=client->msg;
        client->msg=malloc(32);
        memerror(client->msg);
        strcpy(client->msg,"PART #unregisted");
        part(client,ppchans,false,channels,true);
        free(client->msg);
        client->msg=tmp;

        write_sock(client,":%s!%s@%s NOTICE %s :Nick %s registado por ti.\r\n",
                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);

        write_sock(client,":%s!%s@%s NOTICE %s :Não esqueças a tua password!"
                          " Lembra-te que ela e' case sensitive (\"A\" diferente de \"a\")."
                          " Se o nick não for usado por %d dias ele sera' desregistado!\r\n",
                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,REMOVE_NICK_TIMEOUT);

#if FORCE_JOIN_PUTEDO == 1
        tmp=client->msg;
        client->msg=malloc(32);
        memerror(client->msg);
        strcpy(client->msg,"JOIN #putedo");
        join(ppclients,client,channels,ppchans);
        free(client->msg);
        client->msg=tmp;
#endif
}

static void nickserv_info(CLIENTS *client, USERREG **users_regs_lst, CHANS *chans)
{
        USERREG *users_regs;
        char *nick;
        char *mes[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
        long ltmp;
        char **founder=NULL;
        char **access=NULL;
        long f_counter=0;
        long a_counter=0;
        long counter=0;
        int tmp;
        veryshort counter2=0;
        struct tm *tminfo;
        time_t tm_cpy;
        time_t now;

        if (tknum(client->msg,' ') == 2) {
                show_nickserv_help(client,HELP_INFO);
                return;
        }

        if (tknum(client->msg,' ') > 3) {
                write_sock(client,":%s!%s@%s NOTICE %s :Info: Demasiados parametros\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return;
        }

        nick=getoken(client->msg,3,' ');

        check_unused_reg(users_regs_lst,chans);

        users_regs=get_raw_user_reg(*users_regs_lst,nick);

        if (users_regs == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Nick %s não registado.\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);

                free(nick);
                return;
        }

        time(&now);
        if ((compic(nick,client->nick) && users_regs->status == USER_STATUS_IDENTIFIED) || client->ircop) /*Para um ircop ou para o
                                                                                                                    próprio*/
        {
                /*
                        PARA IRCOP OU PARA O PROPRIO

              * orium e' pergunta-m
              * Ultima mask: ...@213.58.166.148
              * Data de registo: Aug 18 09:59:28 2003
              * Ultima vez presente: Nov 13 10:17:42 2003
              * URL: URL
              * E-mail: MAIL
                Founder em 1 canais
                --> #orium,
                Nivel de acesso positivo em 6 canais
                -> #freirada 13, #putedo 15, #spy 15, #setup 5, #strong 5
                --> #ccmi_8.3 5,
              * Online identificado; 1608054 segundos total online identificado
                0 memos

                *********************

                orium e' pergunta-m
                Ultima mask: ...@213.58.166.148
                Data de registo: Aug 18 09:59:28 2003
                Ultima vez presente: Nov 13 10:17:42 2003
                URL: URL
                E-mail: MAIL
                Localização: ...
                Kill: X segs
                Online identificado; 1608054 segundos total online identificado (X,XX horas)
                */

                write_sock(client,":%s!%s@%s NOTICE %s :%s e' %s\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->nick,
                                  (users_regs->nome == NULL) ? "" : users_regs->nome);

                write_sock(client,":%s!%s@%s NOTICE %s :Ultima mask: %s\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->last_mask);

                tm_cpy=users_regs->reg_time;
                tminfo=localtime(&tm_cpy);

                ltmp=(long)(now-users_regs->reg_time);

                write_sock(client,":%s!%s@%s NOTICE %s :Data de registo: %s %d %02d:%02d:%02d %d"
                                  " [Ha' %d dias, %d horas e %d mins]\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,mes[tminfo->tm_mon],tminfo->tm_mday,
                                  tminfo->tm_hour,tminfo->tm_min,tminfo->tm_sec,tminfo->tm_year+1900,
                                  ltmp/60/60/24,ltmp/60/60%24,ltmp/60%60);


                tm_cpy=users_regs->last_time;
                tminfo=localtime(&tm_cpy);
                ltmp=(long) (now-users_regs->last_time);

                write_sock(client,":%s!%s@%s NOTICE %s :Ultima vez presente: %s %d %02d:%02d:%02d %d"
                                  " [Ha' %d dias, %d horas e %d mins]\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,mes[tminfo->tm_mon],tminfo->tm_mday,
                                  tminfo->tm_hour,tminfo->tm_min,tminfo->tm_sec,tminfo->tm_year+1900,
                                  ltmp/60/60/24,ltmp/60/60%24,ltmp/60%60);

                if (users_regs->url != NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :URL: %s\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->url);
                if (users_regs->email != NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :E-mail: %s\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->email);
                if (users_regs->localizacao != NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :Localização: %s\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->localizacao);

                write_sock(client,":%s!%s@%s NOTICE %s :Kill: %d segs\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->kill_timeout);

                while (chans != NULL)
                {
                        if (chans->reg != NULL)
                        {
                                if (compic(chans->reg->founder,users_regs->nick)) /*founder*/
                                {
                                        f_counter++;
                                        founder=realloc(founder,sizeof(*founder)*(f_counter+1));
                                        memerror(founder);

                                        founder[f_counter]=malloc(strlen(chans->name)+1);
                                        memerror(founder[f_counter]);

                                        strcpy(founder[f_counter],chans->name);

                                        founder[f_counter+1]=NULL;
                                }
                                if ((tmp=get_user_access_level(chans->reg->ausers,users_regs->nick)) > 0) /*Acesso positivo*/
                                {
                                        a_counter++;
                                        access=realloc(access,sizeof(*access)*(a_counter+1));
                                        memerror(access);

                                        access[a_counter]=malloc(strlen(chans->name)+5);
                                        memerror(access[a_counter]);

                                        snprintf(access[a_counter],strlen(chans->name)+5,"%s %d",chans->name,(int)tmp);

                                        access[a_counter+1]=NULL;
                                }
                        }

                        chans=chans->next;
                }

                if (founder != NULL)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Founder em %ld canais\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,f_counter);
                        write_sock(client,":%s!%s@%s NOTICE %s :-> ",NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        while (founder[counter] != NULL)
                        {
                                if (!counter2)
                                        write_sock(client,"%s",founder[counter]);
                                else
                                        write_sock(client,", %s",founder[counter]);

                                free(founder[counter]);
                                counter++;
                                counter2++;
                                if (counter2 == 5 && founder[counter] != NULL) {
                                        write_sock(client,"\r\n");
                                        write_sock(client,":%s!%s@%s NOTICE %s :-> ",
                                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                                        counter2=0;
                                }
                        }
                        free(founder);
                        write_sock(client,"\r\n");
                }

                if (access != NULL)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Nivel de acesso positivo em %ld canais\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,a_counter);
                        write_sock(client,":%s!%s@%s NOTICE %s :-> ",NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);

                        counter2=0;
                        counter=0;
                        while (access[counter] != NULL)
                        {
                                if (!counter2)
                                        write_sock(client,"%s",access[counter]);
                                else
                                        write_sock(client,", %s",access[counter]);

                                free(access[counter]);
                                counter++;
                                counter2++;
                                if (counter2 == 5 && access[counter] != NULL) {
                                        write_sock(client,"\r\n");
                                        write_sock(client,":%s!%s@%s NOTICE %s :-> ",
                                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                                        counter2=0;
                                }
                        }
                        free(access);
                        write_sock(client,"\r\n");
                }

                ltmp=now-users_regs->last_time+users_regs->online_time;

                write_sock(client,":%s!%s@%s NOTICE %s :Online identificado; %ld segundos total online identificado"
                                  " [%d dias, %d horas e %d mins]\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,ltmp,
                                  ltmp/60/60/24,ltmp/60/60%24,ltmp/60%60);

                if (users_regs->status != USER_STATUS_OFFLINE && !compic(nick,client->nick))
                        write_sock(client,":%s!%s@%s NOTICE %s :Utilizador esta' online.%s\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,
                                   (users_regs->status == USER_STATUS_TO_IDENTIFY) ? " (Não identificado)" : "");
        }
        else
        {
                /*
                 * NICK e' NOME
                 * Data de registo: Jan 9 02:35:13 2003
                 * Ultima vez presente: Nov 11 22:56:26 2003
                 * URL: URL
                 * E-mail: MAIL
                 * Localização: ...
                 */
                write_sock(client,":%s!%s@%s NOTICE %s :%s e' %s\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->nick,
                                  (users_regs->nome == NULL) ? "" : users_regs->nome);

                tm_cpy=users_regs->reg_time;
                tminfo=localtime(&tm_cpy);

                ltmp=(long) (now-users_regs->reg_time);

                write_sock(client,":%s!%s@%s NOTICE %s :Data de registo: %s %d %02d:%02d:%02d %d"
                                  " [Ha' %d dias, %d horas e %d mins]\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,mes[tminfo->tm_mon],tminfo->tm_mday,
                                  tminfo->tm_hour,tminfo->tm_min,tminfo->tm_sec,tminfo->tm_year+1900,
                                  ltmp/60/60/24,ltmp/60/60%24,ltmp/60%60);


                tm_cpy=users_regs->last_time;
                tminfo=localtime(&tm_cpy);

                ltmp=(long) (now-users_regs->last_time);

                write_sock(client,":%s!%s@%s NOTICE %s :Ultima vez presente: %s %d %02d:%02d:%02d %d"
                                  " [Ha' %d dias, %d horas e %d mins]\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,mes[tminfo->tm_mon],tminfo->tm_mday,
                                  tminfo->tm_hour,tminfo->tm_min,tminfo->tm_sec,tminfo->tm_year+1900,
                                  ltmp/60/60/24,ltmp/60/60%24,ltmp/60%60);

                if (users_regs->url != NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :URL: %s\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->url);
                if (users_regs->email != NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :E-mail: %s\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->email);
                if (users_regs->localizacao != NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :Localização: %s\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,users_regs->localizacao);

                if (users_regs->status != USER_STATUS_OFFLINE)
                        write_sock(client,":%s!%s@%s NOTICE %s :Utilizador esta' online.%s\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,
                                   (users_regs->status == USER_STATUS_TO_IDENTIFY) ? " (Não identificado)" : "");

        }
        free(nick);
}

static void nickserv_set(CLIENTS *client)
{
        char *cmd;

        if (tknum(client->msg,' ') == 2) {
                show_nickserv_help(client,HELP_SET);
                return;
        }

        if (client->reg == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :O nick %s não esta' registado.\r\n",
                                NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para saberes como o registar escreve /%s help register\r\n",
                                NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        if (client->reg->status != USER_STATUS_IDENTIFIED)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Para usares o comando set tens de estar identificado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para te identificares escreve: /%s identify <password>\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        cmd=getoken(client->msg,3,' ');
        if (compic("password",cmd))
        {/*nickserv set password pass new_pass*/
                char *pass;
                char *newpass;
                if (tknum(client->msg,' ') > 5) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Set password: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }
                if (tknum(client->msg,' ') == 3) {
                        show_nickserv_help(client,HELP_SET_PASSWORD);
                        free(cmd);
                        return;
                }
                if (tknum(client->msg,' ') != 5) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Set password: Poucos parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                pass=getoken(client->msg,4,' ');

                if (!comp(pass,client->reg->password)) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Password inválida\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        free(pass);
                        return;
                }
                free(pass);

                newpass=getoken(client->msg,5,' ');

                if (strlen(newpass) > PASSWORD_LEN_LIMIT)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :A password não pode ter mais de %d caracteres\r\n",
                                NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,PASSWORD_LEN_LIMIT);
                        free(cmd);
                        free(newpass);
                        return;
                }

                if (strlen(newpass) < PASSWORD_MIN_LEN)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :A password não pode ter menos de %d caracteres\r\n",
                                NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,PASSWORD_MIN_LEN);
                        free(cmd);
                        free(newpass);
                        return;
                }
                client->reg->password=newpass;
                write_sock(client,":%s!%s@%s NOTICE %s :Password do nick %s alterada.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
        }
        else if (compic("email",cmd))
        {/*nickserv set email email*/
                char *email;

                if (tknum(client->msg,' ') > 4) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Set email: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                email=getoken(client->msg,4,' ');
                if (email == NULL)
                {
                        free(client->reg->email);
                        client->reg->email=NULL;
                        write_sock(client,":%s!%s@%s NOTICE %s :Email apagado.\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                }
                else
                {
                        int counter=0;
                        int ats=0;

                        while (email[counter] != '\0')
                        {
                                if (email[counter] == '@') ats++;

                                counter++;
                        }

                        if (ats != 1) {
                                write_sock(client,":%s!%s@%s NOTICE %s :Email inválido\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                                free(cmd);
                                free(email);
                                return;
                        }
                        free(client->reg->email);
                        client->reg->email=email;
                        write_sock(client,":%s!%s@%s NOTICE %s :Email alterado.\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                }
        }
        else if (compic("url",cmd))
        {
                char *url;

                if (tknum(client->msg,' ') > 4) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Set url: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                url=getoken(client->msg,4,' ');
                if (url == NULL)
                {
                        free(client->reg->url);
                        client->reg->url=NULL;
                        write_sock(client,":%s!%s@%s NOTICE %s :URL apagado.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                }
                else
                {
                        int px=0;
                        char *url_f;

                        if (compictk(url,"http://",7))
                                px=7;

                        if (strlen(&url[px]) == 0)
                        {
                                write_sock(client,":%s!%s@%s NOTICE %s :URL inválido\r\n",
                                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                                free(cmd);
                                free(url);
                                return;
                        }

                        free(client->reg->url);

                        url_f=malloc(strlen(&url[px])+8);
                        memerror(url_f);
                        sprintf(url_f,"http://%s",&url[px]);

                        free(url);
                        client->reg->url=url_f;
                        write_sock(client,":%s!%s@%s NOTICE %s :URL alterado.\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                }
        }
        else if (compic("location",cmd))
        {/*nickserv set location ... ...*/
                if (tknum(client->msg,' ') == 3)
                {
                        free(client->reg->localizacao);
                        client->reg->localizacao=NULL;
                        write_sock(client,":%s!%s@%s NOTICE %s :Location apagada.\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                }
                else
                {
                        int px=0;
                        int counter=0;
                        int s_counter=0;

                        while (client->msg[counter] != '\0')
                        {
                                if (client->msg[counter] == ' ') s_counter++;
                                if (s_counter == 3) {
                                        px=counter+1;
                                        break;
                                }
                                counter++;
                        }

                        free(client->reg->localizacao);
                        client->reg->localizacao=malloc(strlen(&client->msg[px])+1);
                        memerror(client->reg->localizacao);
                        strcpy(client->reg->localizacao,&client->msg[px]);
                        write_sock(client,":%s!%s@%s NOTICE %s :Location alterada.\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                }

        }
        else if (compic("kill",cmd))
        {/*nickserv set kill num*/
                char *snum;
                int num;

                if (tknum(client->msg,' ') > 4) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Set kill: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                if (tknum(client->msg,' ') == 3) {
                        show_nickserv_help(client,HELP_SET_KILL);
                        free(cmd);
                        return;
                }

                if (tknum(client->msg,' ') != 4) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Set kill: Poucos parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                snum=getoken(client->msg,4,' ');
                if (!isstrnum(snum)) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Kill tem de ser numérico (em segundos)\r\n",
                                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,snum);
                        free(cmd);
                        free(snum);
                        return;
                }

                num=atoi(snum);
                free(snum);

                if (num > MAX_KILL_SEGS) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Kill não pode ser superior a %d\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MAX_KILL_SEGS);
                        free(cmd);
                        return;
                }

                if (num < MIN_KILL_SEGS) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Kill não pode ser inferior a %d\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,MIN_KILL_SEGS);
                        free(cmd);
                        return;
                }
                client->reg->kill_timeout=num;
                write_sock(client,":%s!%s@%s NOTICE %s :Kill alterado\r\n",NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
        }
        else
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Comando set %s invalido\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                write_sock(client,":%s!%s@%s NOTICE %s :Para mais informações escreve: /%s help set\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                free(cmd);
                return;
        }

        free(cmd);
        save_userreg(client->reg);
}

static void nickserv_notes(CLIENTS *client)
{
        char *cmd;
        struct reg_notas *notes;

        if (tknum(client->msg,' ') == 2) {
                show_nickserv_help(client,HELP_NOTES);
                return;
        }

        if (client->reg == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :O nick %s não esta' registado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para saberes como o registar escreve /%s help register\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        if (client->reg->status != USER_STATUS_IDENTIFIED)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Para usares o comando notes tens de estar identificado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para te identificares escreve: /%s identify <password>\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        notes=client->reg->notas;

        cmd=getoken(client->msg,3,' ');
        if (compic("add",cmd))
        {/*nickserv notes add nota*/
                int counter=0;
                int s_counter=1;
                char *nota;
                struct reg_notas *pnotes;

                if (tknum(client->msg,' ') == 3)
                {
                        show_nickserv_help(client,HELP_NOTES_ADD);
                        free(cmd);
                        return;
                }

                while (client->msg[counter] != '\0')
                {
                        if (client->msg[counter] == ' ')
                                s_counter++;
                        if (s_counter == 4)
                                break;

                        counter++;
                }
                counter++;

                nota=malloc(strlen(&(client->msg[counter]))+1);
                memerror(nota);
                strcpy(nota,&(client->msg[counter]));

                if (!client->ircop && get_quant_notes_of_nick(client->reg->notas) >= MAX_NOTES)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Não tens espaço para mais notas\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(nota);
                        free(cmd);
                        return;
                }

                pnotes=alloc_note_list(&client->reg->notas);

                pnotes->nota=nota;
                pnotes->num=get_note_max_num(client->reg->notas)+1;

                write_sock(client,":%s!%s@%s NOTICE %s :Nota adicionada.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
        }
        else if (compic("del",cmd))
        {/*nickserv notes del num*/
                char *snum;
                int num=0;
                bool found=false;
                struct reg_notas *p_last_note=notes;

                if (tknum(client->msg,' ') == 3)
                {
                        show_nickserv_help(client,HELP_NOTES_DEL);
                        free(cmd);
                        return;
                }

                if (tknum(client->msg,' ') > 4)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Notes del: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                snum=getoken(client->msg,4,' ');

                if (snum[0] == '#')
                {
                        char *tmp;

                        tmp=snum;

                        snum=malloc(strlen(tmp));
                        memerror(snum);

                        strcpy(snum,&tmp[1]);

                        free(tmp);
                }

                if (!isstrnum(snum))
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Numero da nota inválida!\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(snum);
                        free(cmd);
                        return;
                }

                num=atoi(snum);

                while (notes != NULL)
                {
                        if (num == notes->num)
                        {
                                rm_note_list(&client->reg->notas,notes);

                                free(notes->nota);
                                free(notes);

                                found=true;
                                break;
                        }

                        p_last_note=notes;
                        notes=notes->next;
                }

                if (!found)
                        write_sock(client,":%s!%s@%s NOTICE %s :Nota #%d não existe!\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                else
                        write_sock(client,":%s!%s@%s NOTICE %s :Nota apagada.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);

                free(snum);
        }
        else if (compic("list",cmd))
        {
                if (tknum(client->msg,' ') > 3) {
                        write_sock(client,":%s!%s@%s NOTICE %s :Notes list: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                if (notes == NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :Não tem nenhuma nota.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                else
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Notas:\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        while (notes != NULL)
                        {
                                write_sock(client,":%s!%s@%s NOTICE %s :#%d: %s\r\n",
                                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,notes->num,notes->nota);
                                notes=notes->next;
                        }
                }
        }
        else
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Comando notes %s invalido\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                write_sock(client,":%s!%s@%s NOTICE %s :Para mais informações escreve: /%s help notes\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                free(cmd);
                return;
        }

        free(cmd);
        save_userreg(client->reg);
}

static void nickserv_ajoin(CLIENTS *client, CLIENTS **ppclients, long *channels, CHANS **ppchans)
{
        char *cmd;
        struct reg_ajoin *ajoins;

        if (tknum(client->msg,' ') == 2) {
                show_nickserv_help(client,HELP_NOTES);
                return;
        }

        if (client->reg == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :O nick %s não esta' registado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para saberes como o registar escreve /%s help register\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        if (client->reg->status != USER_STATUS_IDENTIFIED)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Para usares o comando ajoin tens de estar identificado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para te identificares escreve: /%s identify <password>\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        ajoins=client->reg->ajoins;

        cmd=getoken(client->msg,3,' ');
        if (compic("add",cmd))
        {/*nickserv ajoin add chan*/
                char *chan;
                int n_counter=0;
                int counter=0;
                struct reg_ajoin *pajoins;

                if (tknum(client->msg,' ') == 3)
                {
                        show_nickserv_help(client,HELP_AJOIN_ADD);
                        free(cmd);
                        return;
                }

                if (tknum(client->msg,' ') > 4)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin add: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                chan=getoken(client->msg,4,' ');

                if ((chan[0] == '#' && strlen(chan) == 1) || strlen(chan) > MAX_CHANNEL_LEN)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Canal inválido\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(chan);
                        free(cmd);
                        return;
                }

                /*Verifica se canal e' válido*/
                while (chan[counter] != '\0')
                {
                        switch (chan[counter])
                        {
                                case '\7': ;
                                case ' ': ;
                                case ',':
                                {
                                        write_sock(client,":%s!%s@%s NOTICE %s :Canal inválido\r\n",
                                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                                        free(chan);
                                        free(cmd);
                                        return;
                                }
                        }
                        counter++;
                }

                pajoins=ajoins;
                while (pajoins != NULL)
                {
                        n_counter++;

                        if (chan[0] == '#')
                        {
                                if (compic(chan,pajoins->chan))
                                {
                                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin %s ja' existente\r\n",
                                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,chan);
                                        free(chan);
                                        free(cmd);
                                        return;
                                }
                        }
                        else
                        {
                                if (compic(chan,&(pajoins->chan[1])))
                                {
                                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin #%s ja' existente\r\n",
                                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,chan);
                                        free(chan);
                                        free(cmd);
                                        return;
                                }
                        }

                        pajoins=pajoins->next;
                }

                if (!client->ircop && n_counter >= MAX_AJOINS_CHANS)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Não tens espaço para mais ajoins\r\n",
                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(chan);
                        free(cmd);
                        return;
                }

                pajoins=alloc_ajoin_list(&client->reg->ajoins);

                if (chan[0] == '#')
                        pajoins->chan=chan;
                else
                {
                        pajoins->chan=malloc(strlen(chan)+2);
                        memerror(pajoins->chan);

                        pajoins->chan[0]='#';

                        strcpy(&(pajoins->chan[1]),chan);

                        free(chan);
                }

                write_sock(client,":%s!%s@%s NOTICE %s :Ajoin adicionado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
        }
        else if (compic("del",cmd))
        {/*nickserv notes del <chan>*/
                char *chan;
                bool found=false;

                if (tknum(client->msg,' ') == 3)
                {
                        show_nickserv_help(client,HELP_NOTES_DEL);
                        free(cmd);
                        return;
                }

                if (tknum(client->msg,' ') > 4)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin del: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                chan=getoken(client->msg,4,' ');

                if (chan[0] != '#')
                {
                        char *tmp;

                        tmp=chan;

                        chan=malloc(strlen(chan)+2);
                        memerror(chan);

                        chan[0]='#';

                        strcpy(&(chan[1]),tmp);

                        free(tmp);
                }

                while (ajoins != NULL)
                {
                        if (compic(chan,ajoins->chan))
                        {
                                rm_ajoin_list(&client->reg->ajoins,ajoins);

                                free(ajoins->chan);
                                free(ajoins);

                                found=true;
                                break;
                        }

                        ajoins=ajoins->next;
                }


                if (!found)
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin %s não existe!\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,chan);
                else
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin apagado\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);

                free(chan);
        }
        else if (compic("list",cmd))
        {
                if (tknum(client->msg,' ') > 3)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin list: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                if (ajoins == NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :Não tem nenhum ajoin.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                else
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoins:\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        while (ajoins != NULL)
                        {
                                write_sock(client,":%s!%s@%s NOTICE %s :%s\r\n",
                                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,ajoins->chan);
                                ajoins=ajoins->next;
                        }
                }
        }
        else if (compic("now",cmd))
        {
                if (tknum(client->msg,' ') > 3)
                {
                        write_sock(client,":%s!%s@%s NOTICE %s :Ajoin now: Demasiados parametros\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                        free(cmd);
                        return;
                }

                if (ajoins == NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :Não tem nenhum ajoin.\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                else
                        ajoin_all(ajoins,ppclients,client,channels,ppchans);
        }
        else
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Comando ajoin %s invalido\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,cmd);
                write_sock(client,":%s!%s@%s NOTICE %s :Para mais informações escreve: /%s help ajoin\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                free(cmd);
                return;
        }

        free(cmd);
        save_userreg(client->reg);
}

static void nickserv_drop(CLIENTS *client, USERREG **users_regs_lst, CHANS *chans)
{
        char *pw;
        USERREG *target=client->reg;

        if (tknum(client->msg,' ') == 2)
        {
                show_nickserv_help(client,HELP_DROP);
                return;
        }

        if (client->reg == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :O nick %s não esta' registado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
                return;
        }

        if (client->reg->status != USER_STATUS_IDENTIFIED)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Para usares o comando drop tens de estar identificado.\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                write_sock(client,":%s!%s@%s NOTICE %s :Para te identificares escreve: /%s identify <password>\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME);
                return;
        }

        if (tknum(client->msg,' ') > 3)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Drop: Demasiados parametros\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return;
        }

        pw=getoken(client->msg,3,' ');

        if (!comp(pw,client->reg->password))
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Password inválida\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);

                free(pw);
                return;
        }
        free(pw);

        rm_user_reg_list(users_regs_lst,target);

        rm_ref_to_nick_reg(target->nick,chans);

        free_ajoins_and_notes(target);

        free(target->nick);
        free(target->password);
        free(target->nome);
        free(target->email);
        free(target->url);
        free(target->localizacao);
        free(target->last_mask);
        free(target);

        rm_user_reg_file(client->nick);

        client->reg=NULL;
        write_sock(client,":%s!%s@%s NOTICE %s :Nick %s desregistado.\r\n",
                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,client->nick);
}

static bool nickserv_ghost(CLIENTS *client, USERREG *user_reg_lst, CLIENTS **ppclients)
{/*nickserv drop nick password*/
        USERREG *user_regs;
        CLIENTS *tclient;
        char *nick;
        char *pw;

        if (tknum(client->msg,' ') == 2) {
                show_nickserv_help(client,HELP_GHOST);
                return false;
        }

        if (tknum(client->msg,' ') > 4) {
                write_sock(client,":%s!%s@%s NOTICE %s :Ghost: Demasiados parametros\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return false;
        }

        if (tknum(client->msg,' ') != 4) {
                write_sock(client,":%s!%s@%s NOTICE %s :Ghost: Poucos parametros\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return false;
        }

        if (client->reg != NULL) if (client->reg->status != USER_STATUS_IDENTIFIED)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Para fazer um ghost com um nick registado tens de estar identificado\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return false;
        }

        nick=getoken(client->msg,3,' ');

        if (compic(nick,client->nick))
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Não podes fazer um ghost kill a ti mesmo\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                free(nick);
                return false;
        }

        user_regs=get_raw_user_reg(user_reg_lst,nick);

        if (user_regs == NULL)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Nick %s não esta' registado!\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);
                free(nick);
                return false;
        }

        if (user_regs->status == USER_STATUS_OFFLINE)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Nick %s não esta' online!\r\n",
                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);
                free(nick);
                return false;
        }

        free(nick);

        pw=getoken(client->msg,4,' ');

        if (!comp(pw,user_regs->password))
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Ghost: Password inválida!\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                free(pw);
                return false;
        }

        free(pw);

        tclient=get_client(*ppclients,user_regs->nick);

        if (tclient == NULL)
                return false;

        write_sock(tclient,":%s!%s@%s KILL killed :%s (ghost utilizado por %s)\r\n",
                   tclient->nick,USER_NAME,tclient->md5_ip,NICKSERV_NAME,client->nick);

        write_sock(tclient,"ERROR :Closing Link: %s[%s@%s] by %s (Killed (%s (ghost utilizado por %s)))\r\n",
                   tclient->nick,USER_NAME,tclient->md5_ip,NICKSERV_NAME,NICKSERV_NAME,client->nick);

        send_to_all(tclient,":%s!%s@%s QUIT :Killed (%s (ghost utilizado por %s))\r\n",
                    tclient->nick,USER_NAME,tclient->md5_ip,NICKSERV_NAME,client->nick);

        close(tclient->sd);
        remove_connection(ppclients,tclient);

        write_sock(client,":%s!%s@%s NOTICE %s :Ghost com o teu nick foi removido.\r\n",
                          NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
        return true;
}

static void nickserv_status(CLIENTS *client, USERREG *users_regs_lst)
{
        USERREG *users_regs;
        int n_counter=3;
        char *nick;

        if (tknum(client->msg,' ') == 2) {
                show_nickserv_help(client,HELP_STATUS);
                return;
        }

        if (tknum(client->msg,' ') > MAX_STATUS_PARAMS+2)
        {
                write_sock(client,":%s!%s@%s NOTICE %s :Status: Demasiados parametros\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick);
                return;
        }

        nick=getoken(client->msg,n_counter++,' ');
        while (nick != NULL)
        {
                users_regs=get_raw_user_reg(users_regs_lst,nick);

                if (users_regs == NULL)
                        write_sock(client,":%s!%s@%s NOTICE %s :STATUS %s 0\r\n",
                                   NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);
                else
                {
                        if (users_regs->status == USER_STATUS_OFFLINE)
                                write_sock(client,":%s!%s@%s NOTICE %s :STATUS %s 0\r\n",
                                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);
                        if (users_regs->status == USER_STATUS_IDENTIFIED)
                                write_sock(client,":%s!%s@%s NOTICE %s :STATUS %s 3\r\n",
                                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);
                        if (users_regs->status == USER_STATUS_TO_IDENTIFY)
                                write_sock(client,":%s!%s@%s NOTICE %s :STATUS %s 1\r\n",
                                           NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,nick);
                }

                free(nick);
                nick=getoken(client->msg,n_counter++,' ');
        }
}

void nickserv(CLIENTS *client, USERREG **users_regs, CHANS **ppchans, long *channels, CLIENTS **ppclients, long *users)
{
        char *command;

        if (tknum(client->msg,' ') == 1) {
                show_nickserv_help(client,HELP_MAIN);
                return;
        }

        command=getoken(client->msg,2,' ');

        if (compic(command,"help"))
        {
                char *cmd2;

                if (tknum(client->msg,' ') == 2) {
                        show_nickserv_help(client,HELP_MAIN);
                        free(command);
                        return;
                }
                cmd2=getoken(client->msg,3,' ');
                if (tknum(client->msg,' ') == 3)
                {
                        if (compic(cmd2,"identify"))
                        {
                                show_nickserv_help(client,HELP_IDENTIFY);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"register"))
                        {
                                show_nickserv_help(client,HELP_REGISTER);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"info"))
                        {
                                show_nickserv_help(client,HELP_INFO);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"set"))
                        {
                                show_nickserv_help(client,HELP_SET);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"drop"))
                        {
                                show_nickserv_help(client,HELP_DROP);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"ghost"))
                        {
                                show_nickserv_help(client,HELP_GHOST);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"status"))
                        {
                                show_nickserv_help(client,HELP_STATUS);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"notes"))
                        {
                                show_nickserv_help(client,HELP_NOTES);
                                free(command);
                                free(cmd2);
                                return;
                        }
                        if (compic(cmd2,"ajoin"))
                        {
                                show_nickserv_help(client,HELP_AJOIN);
                                free(command);
                                free(cmd2);
                                return;
                        }
                }
                if (tknum(client->msg,' ') >= 4)
                {
                        if (compic(cmd2,"set"))
                        {
                                char *cmd3;
                                cmd3=getoken(client->msg,4,' ');
                                if (compic(cmd3,"password"))
                                {
                                        show_nickserv_help(client,HELP_SET_PASSWORD);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"email"))
                                {
                                        show_nickserv_help(client,HELP_SET_EMAIL);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"url"))
                                {
                                        show_nickserv_help(client,HELP_SET_URL);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"location"))
                                {
                                        show_nickserv_help(client,HELP_SET_LOCATION);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"kill"))
                                {
                                        show_nickserv_help(client,HELP_SET_KILL);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                show_nickserv_help(client,HELP_UNKNOWN_SET_COMMAND);
                                free(command);
                                free(cmd2);
                                free(cmd3);
                                return;
                        }
                        if (compic(cmd2,"notes"))
                        {
                                char *cmd3;
                                cmd3=getoken(client->msg,4,' ');
                                if (compic(cmd3,"add"))
                                {
                                        show_nickserv_help(client,HELP_NOTES_ADD);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"del"))
                                {
                                        show_nickserv_help(client,HELP_NOTES_DEL);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"list"))
                                {
                                        show_nickserv_help(client,HELP_NOTES_LIST);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                show_nickserv_help(client,HELP_UNKNOWN_NOTES_COMMAND);
                                free(command);
                                free(cmd2);
                                free(cmd3);
                                return;
                        }
                        if (compic(cmd2,"ajoin"))
                        {
                                char *cmd3;
                                cmd3=getoken(client->msg,4,' ');
                                if (compic(cmd3,"add"))
                                {
                                        show_nickserv_help(client,HELP_AJOIN_ADD);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"del"))
                                {
                                        show_nickserv_help(client,HELP_AJOIN_DEL);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"list"))
                                {
                                        show_nickserv_help(client,HELP_AJOIN_LIST);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                if (compic(cmd3,"now"))
                                {
                                        show_nickserv_help(client,HELP_AJOIN_NOW);
                                        free(command);
                                        free(cmd2);
                                        free(cmd3);
                                        return;
                                }
                                show_nickserv_help(client,HELP_UNKNOWN_AJOIN_COMMAND);
                                free(command);
                                free(cmd2);
                                free(cmd3);
                                return;
                        }
                }

                show_nickserv_help(client,HELP_UNKNOWN_COMMAND);
                free(command);
                free(cmd2);
                return;
        }

        if (nickserv_iscommand(command))
        {
                if (compic(command,"identify")) nickserv_identify(client,ppchans,channels,ppclients);
                if (compic(command,"register")) nickserv_register(client,ppchans,users_regs,channels,ppclients);
                if (compic(command,"info")) nickserv_info(client,users_regs,*ppchans);
                if (compic(command,"set")) nickserv_set(client);
                if (compic(command,"drop")) nickserv_drop(client,users_regs,*ppchans);
                if (compic(command,"status")) nickserv_status(client,*users_regs);
                if (compic(command,"notes")) nickserv_notes(client);
                if (compic(command,"ajoin")) nickserv_ajoin(client,ppclients,channels,ppchans);
                if (compic(command,"ghost"))
                        if (nickserv_ghost(client,*users_regs,ppclients))
                        {
                                check_chans(ppchans,channels);
                                (*users)--;
                        }
        }
        else
                write_sock(client,":%s!%s@%s NOTICE %s :Comando %s desconhecido. \"/%s help\" para ajuda.\r\n",
                                  NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,command,NICKSERV_NAME);

        free(command);
}

static bool nickserv_iscommand(char *cmd)
{
        if (compic(cmd,"identify")) return true;
        if (compic(cmd,"register")) return true;
        if (compic(cmd,"info")) return true;
        if (compic(cmd,"set")) return true;
        if (compic(cmd,"drop")) return true;
        if (compic(cmd,"ghost")) return true;
        if (compic(cmd,"status")) return true;
        if (compic(cmd,"notes")) return true;
        if (compic(cmd,"ajoin")) return true;

        return false;
}

USERREG *get_user_reg(CLIENTS *client, USERREG **users_regs_lst, CHANS *chans)
{
        USERREG *users_regs;
        USERREG *regs_lst;

        check_unused_reg(users_regs_lst,chans);

        users_regs=*users_regs_lst;
        regs_lst=users_regs;

        while (regs_lst != NULL)
        {
                if (compic(regs_lst->nick,client->nick))
                {
                        time(&(regs_lst->ident_timeout));
                        regs_lst->ident_timeout+=regs_lst->kill_timeout;
                        regs_lst->status=USER_STATUS_TO_IDENTIFY;

                        if (client->do_welcome == 0)
                                write_sock(client,":%s!%s@%s NOTICE %s :Nick registado e protegido!"
                                                        " Se e' teu escreve /%s identify <password>."
                                                        " Tens %d segs para o fazer ou mudar de nick!\r\n",
                                                        NICKSERV_NAME,USER_NAME,SERVER_NAME,client->nick,NICKSERV_NAME,
                                                        regs_lst->kill_timeout);
                        return regs_lst;
                }

                regs_lst=regs_lst->next;
        }

        return NULL;
}

void save_userreg(USERREG *userreg)
{
        FILE *reg;
        char *filename;
        char *tmp;
        int counter=0;

        tmp=malloc(strlen(userreg->nick)+1);
        memerror(tmp);

        while (userreg->nick[counter] != '\0')
        {
                tmp[counter]=tolower(userreg->nick[counter]);

                counter++;
        }
        tmp[counter]='\0';

        asprintf(&filename,"%s/.%s/nickserv/registos/%s",getenv("HOME"),FREEIRCD_NAME,tmp);

        if (filename == NULL) {
                fprintf(stderr,"Erro ao tentar gravar registo do nick (asprintf)\n");
                return;
        }

        reg=fopen(filename,"w");
        ndb_free(filename);

        if (reg == NULL)
        {
                fprintf(stderr,"Erro ao tentar gravar registo do nick (fopen)\n");
                free(tmp);
                return;
        }

        fprintf(reg,"%s\n",userreg->nick);
        fprintf(reg,"%s\n",userreg->password);
        fprintf(reg,"%s\n",userreg->last_mask);
        fprintf(reg,"%s\n",(userreg->nome == NULL) ? "" : userreg->nome);
        fprintf(reg,"%s\n",(userreg->email == NULL) ? "" : userreg->email);
        fprintf(reg,"%s\n",(userreg->url == NULL) ? "" : userreg->url);
        fprintf(reg,"%s\n",(userreg->localizacao == NULL) ? "" : userreg->localizacao);

        fprintf(reg,"%ld\n",(long)userreg->reg_time);
        fprintf(reg,"%ld\n",(long)userreg->last_time);
        fprintf(reg,"%ld\n",(long)userreg->online_time);

        fprintf(reg,"%d\n",userreg->kill_timeout);

        fprintf(reg,"%d\n",(int)userreg->never_unreg);

        fclose(reg);

        if (userreg->notas != NULL)
        {
                struct reg_notas *notas=userreg->notas;

                asprintf(&filename,"%s/.%s/nickserv/notas/%s",getenv("HOME"),FREEIRCD_NAME,tmp);

                if (filename == NULL)
                {
                        fprintf(stderr,"Erro ao tentar gravar notas do nick (asprintf)\n");
                        free(tmp);
                        return;
                }

                reg=fopen(filename,"w");
                ndb_free(filename);

                if (reg == NULL)
                {
                        fprintf(stderr,"Erro ao tentar gravar notas do nick (fopen)\n");
                        free(tmp);
                        return;
                }

                while (notas != NULL)
                {
                        fprintf(reg,"%d\n",notas->num);
                        fprintf(reg,"%s\n",notas->nota);

                        notas=notas->next;
                }

                fclose(reg);
        }
        else
        {
                asprintf(&filename,"%s/.%s/nickserv/notas/%s",getenv("HOME"),FREEIRCD_NAME,tmp);

                if (filename == NULL)
                {
                        fprintf(stderr,"Erro ao tentar gravar notas do nick (asprintf)\n");
                        free(tmp);
                        return;
                }

                remove(filename);
                ndb_free(filename);
        }

        if (userreg->ajoins != NULL)
        {
                struct reg_ajoin *ajoins;

                asprintf(&filename,"%s/.%s/nickserv/ajoins/%s",getenv("HOME"),FREEIRCD_NAME,tmp);

                if (filename == NULL)
                {
                        fprintf(stderr,"Erro ao tentar gravar ajoins do nick (asprintf)\n");
                        free(tmp);
                        return;
                }

                reg=fopen(filename,"w");
                ndb_free(filename);

                if (reg == NULL)
                {
                        fprintf(stderr,"Erro ao tentar gravar ajoins do nick (fopen)\n");
                        free(tmp);
                        return;
                }

                ajoins=userreg->ajoins;
                while (ajoins != NULL)
                {
                        fprintf(reg,"%s\n",ajoins->chan);

                        ajoins=ajoins->next;
                }

                fclose(reg);
        }
        else
        {
                asprintf(&filename,"%s/.%s/nickserv/ajoins/%s",getenv("HOME"),FREEIRCD_NAME,tmp);

                if (filename == NULL)
                {
                        fprintf(stderr,"Erro ao tentar gravar ajoins do nick (asprintf)\n");
                        free(tmp);
                        return;
                }

                remove(filename);
                ndb_free(filename);
        }

        free(tmp);
}

void load_userreg(USERREG **ppuserreg)
{
        FILE *reg;
        DIR *nicks;
        USERREG *userreg=*ppuserreg;
        char *dirname;
        char *filename;
        char *line;
        struct dirent *nick_entry;
        struct reg_notas *pnotas=NULL;
        struct reg_ajoin *pajoins;
        bool found;
        veryshort num_nota;

        asprintf(&dirname,"%s/.%s/nickserv/registos/",getenv("HOME"),FREEIRCD_NAME);

        if (dirname == NULL)
        {
                fprintf(stderr,"Erro ao tentar ler registo dos nicks (asprintf)\n");
                return;
        }

        nicks=opendir(dirname);

        if (nicks == NULL)
        {
                fprintf(stderr,"Erro ao tentar ler registo dos nicks (opendir)\n");
                ndb_free(dirname);
                return;
        }

        while((nick_entry=readdir(nicks)) != NULL)
        {
                if (!comp(nick_entry->d_name,".") && !comp(nick_entry->d_name,".."))
                {
                        asprintf(&filename,"%s%s",dirname,nick_entry->d_name);
                        if (filename == NULL)
                        {
                                fprintf(stderr,"Erro ao tentar ler registo do nick %s (asprintf)\n",nick_entry->d_name);
                                ndb_free(filename);
                                continue;
                        }

                        reg=fopen(filename,"r");
                        ndb_free(filename);
                        if (reg == NULL)
                        {
                                fprintf(stderr,"Erro ao tentar ler registo do nick %s (fopen)\n",nick_entry->d_name);
                                continue;
                        }

                        userreg=alloc_user_reg_list(ppuserreg);

                        fggets(&(userreg->nick),reg);
                        fggets(&(userreg->password),reg);
                        fggets(&(userreg->last_mask),reg);
                        fggets(&(userreg->nome),reg);
                        fggets(&(userreg->email),reg);
                        fggets(&(userreg->url),reg);
                        fggets(&(userreg->localizacao),reg);

                        if (strlen(userreg->nome) == 0)
                        {
                                free(userreg->nome);
                                userreg->nome=NULL;
                        }

                        if (strlen(userreg->email) == 0)
                        {
                                free(userreg->email);
                                userreg->email=NULL;
                        }

                        if (strlen(userreg->url) == 0)
                        {
                                free(userreg->url);
                                userreg->url=NULL;
                        }

                        if (strlen(userreg->localizacao) == 0)
                        {
                                free(userreg->localizacao);
                                userreg->localizacao=NULL;
                        }

                        fggets(&line,reg);
                        userreg->reg_time=atol(line);
                        free(line);

                        fggets(&line,reg);
                        userreg->last_time=atol(line);
                        free(line);

                        fggets(&line,reg);
                        userreg->online_time=atol(line);
                        free(line);

                        fggets(&line,reg);
                        userreg->kill_timeout=atoi(line);
                        free(line);

                        fggets(&line,reg);
                        userreg->never_unreg=(bool)atoi(line);
                        free(line);

                        userreg->notas=NULL;
                        userreg->ajoins=NULL;
                        userreg->user=NULL;
                        userreg->status=USER_STATUS_OFFLINE;

                        fclose(reg);
                }
        }

        ndb_free(dirname);
        closedir(nicks);

        asprintf(&dirname,"%s/.%s/nickserv/notas/",getenv("HOME"),FREEIRCD_NAME);

        if (dirname == NULL)
        {
                fprintf(stderr,"Erro ao tentar ler notas dos nicks (asprintf)\n");
                return;
        }

        nicks=opendir(dirname);

        if (nicks == NULL)
        {
                fprintf(stderr,"Erro ao tentar ler notas dos nicks (opendir)\n");
                ndb_free(dirname);
                return;
        }

        while((nick_entry=readdir(nicks)) != NULL)
        {
                if (!comp(nick_entry->d_name,".") && !comp(nick_entry->d_name,".."))
                {
                        asprintf(&filename,"%s%s",dirname,nick_entry->d_name);
                        if (filename == NULL)
                        {
                                fprintf(stderr,"Erro ao tentar ler notas do nick %s (asprintf)\n",nick_entry->d_name);
                                ndb_free(filename);
                                continue;
                        }

                        found=false;
                        userreg=*ppuserreg;

                        while (userreg != NULL)
                        {
                                if (compic(userreg->nick,nick_entry->d_name))
                                {
                                        found=true;
                                        break;
                                }

                                userreg=userreg->next;
                        }

                        if (!found)
                        {
                                fprintf(stderr,"Registo do nick %s não encontrado\n",nick_entry->d_name);
                                continue;
                        }

                        reg=fopen(filename,"r");
                        ndb_free(filename);
                        if (reg == NULL)
                        {
                                fprintf(stderr,"Erro ao tentar ler notas dos nicks (fopen)\n");
                                continue;
                        }

                        num_nota=0;
                        while (fggets(&line,reg) == GGETS_OK)
                        {
                                if (strlen(line) == 0)
                                {
                                        free(line);
                                        break;
                                }

                                if (!num_nota)
                                {
                                        pnotas=alloc_note_list(&userreg->notas);

                                        pnotas->num=atoi(line);
                                        free(line);
                                        num_nota=1;
                                }
                                else /*nota*/
                                {
                                        pnotas->nota=line;
                                        num_nota=0;
                                }
                        }
                        fclose(reg);
                }
        }

        ndb_free(dirname);
        closedir(nicks);

        asprintf(&dirname,"%s/.%s/nickserv/ajoins/",getenv("HOME"),FREEIRCD_NAME);

        if (dirname == NULL)
        {
                fprintf(stderr,"Erro ao tentar ler ajoins dos nicks (asprintf)\n");
                return;
        }

        nicks=opendir(dirname);

        if (nicks == NULL)
        {
                fprintf(stderr,"Erro ao tentar ler ajoins dos nicks (opendir)\n");
                ndb_free(dirname);
                return;
        }

        while((nick_entry=readdir(nicks)) != NULL)
        {
                if (!comp(nick_entry->d_name,".") && !comp(nick_entry->d_name,".."))
                {
                        asprintf(&filename,"%s%s",dirname,nick_entry->d_name);
                        if (filename == NULL)
                        {
                                fprintf(stderr,"Erro ao tentar ler ajoins do nick %s (asprintf)\n",nick_entry->d_name);
                                ndb_free(filename);
                                continue;
                        }

                        userreg=get_raw_user_reg(*ppuserreg,nick_entry->d_name);

                        if (userreg == NULL)
                        {
                                fprintf(stderr,"Registo do nick %s não encontrado\n",nick_entry->d_name);
                                continue;
                        }

                        reg=fopen(filename,"r");
                        ndb_free(filename);
                        if (reg == NULL)
                        {
                                fprintf(stderr,"Erro ao tentar ler ajoins dos nicks (fopen)\n");
                                continue;
                        }

                        while (fggets(&line,reg) == GGETS_OK)
                        {
                                if (strlen(line) == 0)
                                {
                                        free(line);
                                        break;
                                }

                                pajoins=alloc_ajoin_list(&userreg->ajoins);

                                pajoins->chan=line;
                        }
                        fclose(reg);
                }
        }

        ndb_free(dirname);
        closedir(nicks);
}

static void rm_user_reg_file(char *nick)
{
        char *filename;
        char *tmp;
        int counter=0;

        tmp=malloc(strlen(nick)+1);
        memerror(tmp);

        while (nick[counter] != '\0')
        {
                tmp[counter]=tolower(nick[counter]);

                counter++;
        }
        tmp[counter]='\0';

        asprintf(&filename,"%s/.%s/nickserv/registos/%s",getenv("HOME"),FREEIRCD_NAME,tmp);
        if (filename == NULL) {
                fprintf(stderr,"Erro ao tentar remover registo do nick %s (asprintf)\n",nick);
                return;
        }

        remove(filename);
        ndb_free(filename);

        asprintf(&filename,"%s/.%s/nickserv/ajoins/%s",getenv("HOME"),FREEIRCD_NAME,tmp);
        if (filename == NULL) {
                fprintf(stderr,"Erro ao tentar remover ajoins do nick %s (asprintf)\n",nick);
                return;
        }

        remove(filename);
        ndb_free(filename);

        asprintf(&filename,"%s/.%s/nickserv/notas/%s",getenv("HOME"),FREEIRCD_NAME,tmp);
        if (filename == NULL) {
                fprintf(stderr,"Erro ao tentar remover notas do nick %s (asprintf)\n",nick);
                return;
        }

        remove(filename);

        ndb_free(filename);
        free(tmp);
}

void check_unused_reg(USERREG **user_regs_lst, CHANS *chans)
{
        USERREG *user_reg=*user_regs_lst;
        USERREG *next_one;
        time_t now;

        time(&now);

        while (user_reg != NULL)
        {
                if (user_reg->status == USER_STATUS_OFFLINE && !user_reg->never_unreg
                    && (now-user_reg->last_time) > (REMOVE_NICK_TIMEOUT*24*60*60))
                {
                        next_one=user_reg->next;
                        rm_user_reg_list(user_regs_lst,user_reg);

                        rm_user_reg_file(user_reg->nick);

                        rm_ref_to_nick_reg(user_reg->nick,chans);

                        printf("Removido nick %s por falta de utilização\n",user_reg->nick);
                        free_ajoins_and_notes(user_reg);
                        free(user_reg->nick);
                        free(user_reg->password);
                        free(user_reg->nome);
                        free(user_reg->email);
                        free(user_reg->url);
                        free(user_reg->localizacao);
                        free(user_reg->last_mask);
                        free(user_reg);

                        user_reg=next_one;
                        continue;
                }

                user_reg=user_reg->next;
        }
}

static void free_ajoins_and_notes(USERREG *target)
{
        struct reg_notas *pnotes;
        struct reg_ajoin *pajoins;

        while (target->notas != NULL)
        {
                pnotes=target->notas;
                rm_ajoin_list(&target->notas,pnotes);

                free(pnotes->nota);
                free(pnotes);
        }

        while (target->ajoins != NULL)
        {
                pajoins=target->ajoins;
                rm_ajoin_list(&target->ajoins,pajoins);

                free(pajoins->chan);
                free(pajoins);
        }
}

static void rm_ref_to_nick_reg(char *nick, CHANS *chans)
{
        /*Apagar da lista de accesso dos canais.
          apagar da lista de akick dos canais
          apagar da lista de bans dos canais (e informar toda a gente)
          Se for founder da' o canal...*/
}

static void ajoin_all(struct reg_ajoin *ajoins, CLIENTS **ppclients, CLIENTS *client, long *channels, CHANS **ppchans)
{
        char *tmp;

        tmp=client->msg;

        while (ajoins != NULL)
        {
                client->msg=malloc(strlen(ajoins->chan)+6);
                memerror(client->msg);

                sprintf(client->msg,"JOIN %s",ajoins->chan);

                join(ppclients,client,channels,ppchans);
                free(client->msg);

                ajoins=ajoins->next;
        }

        client->msg=tmp;
}
